

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

//import Cargo.Frame;

/*
 A: 1.0 x 1.0 x 2.0
 B: 1.0 x 1.5 x 2.0
 C: 1.5 x 1.5 x 1.5
 cargospace: 16.5 long, 2.5 wide, 4.0 high
 2x
 A: 2x2x4
 B: 2x3x4
 C: 3x3x3
 Cont: 33x5x8
 */

public class Bruteforce extends JFrame {
	JFrame myFrame =new JFrame();
	private  int delay = 0;
	private  Timer myTimer;
         public int[][][] container = new int[5][5][5];
      //  private int[][][] container = new int[12][12][6];
        private int[][] boxes = {
                        // {box number,xDim,yDim,zDim}

                        // Box A, 3 combos
                        { 1, 2, 4, 2 }, { 2, 2, 2, 4 }, { 3, 4, 2, 2 },

                        // Box B, 6 combos
                        { 4, 4, 3, 2 }, { 5, 4, 2, 3 }, { 6, 2, 4, 3 }, { 7, 3, 4, 2 }, { 8, 2, 3, 4 }, { 9, 3, 2, 4 },

                        // Box C, 1 Combo
                        { 10, 3, 3, 3 } };
        
        
    	int[][] pentos={
    			{1,	0,0,0,	1,0,0,		0,1,0,		0,2,0,		0,3,0},		// L
    			
    			{1,	0,0,0,	1,0,0,		1,1,0,		1,2,0,		1,3,0},
    			
    			
    			
    			{1,	1,0,0,		1,1,0,		1,2,0,		0,3,0,	1,3,0},
    			
    			{1,	0,0,0,		0,1,0,		0,2,0,		0,3,0,	1,3,0},
    			
    			
    			
    			
    			{1,	0,0,0,		0,1,0,	1,1,0,	2,1,0,	3,1,0},
    			
    			{1,	3,0,0,		0,1,0,	1,1,0,	2,1,0,	3,1,0},
    			
    			{1,	0,0,0,	1,0,0,	2,0,0,	3,0,0,		3,1,0},
    			
    			{1,	0,0,0,	1,0,0,	2,0,0,	3,0,0,		0,1,0},
    			
    			
    			{1,	0,0,0,		0,1,0,		0,2,0,		0,3,0,
    													0,3,1,},
    			
    			
    			{1,										0,3,0,
    				0,0,1,		0,1,1,		0,2,1,		0,3,1},
    				
    				
    				
    			{1,	0,0,0,		0,1,0,		0,2,0,		0,3,0,
    				0,0,1,},
    				
    				
    			{1,	0,0,0,
    				0,0,1,		0,1,1,		0,2,1,		0,3,1},
    				
    				
    			{1,	0,0,0,		0,1,0,
    							0,1,1,
    							0,1,2,
    							0,1,3},
    							
    							
    			{1,	0,0,0,		0,1,0,
    				0,0,1,
    				0,0,2,
    				0,0,3},
    				
    				
    			{1,				0,1,0,
    							0,1,1,
    							0,1,2,
    				0,0,3,		0,1,3},
    				
    				
    			{1,	0,0,0,
    				0,0,1,
    				0,0,2,
    				0,0,3,		0,1,3},
    			
    			
    			{1,	0,0,0,	1,0,0,	2,0,0,	3,0,0,		
    				0,0,1},
    				
    				
    			{1,	0,0,0,		
    				0,0,1,	1,0,1,	2,0,1,	3,0,1},
    				
    				
    			{1,	0,0,0,	1,0,0,	2,0,0,	3,0,0,		
    										3,0,1},
    										
    										
    			{1,							3,0,0,		
    				0,0,1,	1,0,1,	2,0,1,	3,0,1},
    				
    				
    			{1,	0,0,0,	1,0,0,
    						1,0,1,
    						1,0,2,
    						1,0,3},
    						
    						
    			{1,	0,0,0,	1,0,0,
    				0,0,1,
    				0,0,2,
    				0,0,3},
    				
    				
    			{1,	0,0,0,
    				0,0,1,
    				0,0,2,
    				0,0,3,	1,0,3},
    				
    				
    			{1,			1,0,0,
    						1,0,1,
    						1,0,2,
    				0,0,3,	1,0,3},
    			
    			
    			
    			
    			{2,	0,0,0,	1,0,0,		0,1,0,	1,1,0,		1,2,0},		//P
    			
    			{2,	0,0,0,	1,0,0,		0,1,0,	1,1,0,		0,2,0},
    			
    			{2,	1,0,0,		0,1,0,	1,1,0,		0,2,0,	1,2,0},
    			
    			{2,	0,0,0,		0,1,0,	1,1,0,		0,2,0,	1,2,0},
    			
    			{2,	1,0,0,	2,0,0,		0,1,0,	1,1,0,	2,1,0},
    			
    			{2,	0,0,0,	1,0,0,		0,1,0,	1,1,0,	2,1,0},
    			
    			{2,	0,0,0,	1,0,0,	2,0,0,		1,1,0,	2,1,0},
    			
    			{2,	0,0,0,	1,0,0,	2,0,0,		0,1,0,	1,1,0},
    			
    			
    			
    			{2,	0,0,0,		0,1,0,		0,2,0,
    				0,0,1,		0,1,1},
    				
    			{2,	0,0,0,		0,1,0,
    				0,0,1,		0,1,1,		0,2,1},
    				
    				
    			{2,	0,0,0,		0,1,0,		0,2,0,
    				0,1,1,		0,2,1},
    				
    				
    			{2,				0,1,0,		0,2,0,
    				0,0,1,		0,1,1,		0,2,1},
    				
    			{2,	0,0,0,		0,1,0,
    				0,0,1,		0,1,1,
    							0,1,2},
    							
    							
    			{2,				0,1,0,
    				0,0,1,		0,1,1,
    				0,0,2,		0,1,2},
    				
    				
    			{2,	0,0,0,		0,1,0,
    				0,0,1,		0,1,1,
    				0,0,2},
    				
    				
    			{2,	0,0,0,
    				0,0,1,		0,1,1,
    				0,0,2,		0,1,2},
    			
    			
    			{2,	0,0,0,	1,0,0,
    				0,0,1,	1,0,1,
    						1,0,2},
    						
    			{2,	0,0,0,	1,0,0,
    				0,0,1,	1,0,1,
    				0,0,2},
    				
    				
    			{2,			1,0,0,
    				0,0,1,	1,0,1,
    				0,0,1,	1,0,2},
    				
    				
    			{2,	0,0,0,
    				0,0,1,	1,0,1,
    				0,0,2,	1,0,2},
    				
    				
    			{2,			1,0,0,	2,0,0,
    				0,0,1,	1,0,1,	2,0,1},
    				
    				
    			{2,	0,0,0,	1,0,0,
    				0,0,1,	1,0,1,	2,0,1},
    				
    				
    			{2,	0,0,0,	1,0,0,	2,0,0,
    						1,0,1,	2,0,1},
    						
    						
    			{2,	0,0,0,	1,0,0,	2,0,0,
    				0,0,1,	1,0,1},
    			
    			
    			
    			
    			{3,	0,0,0,	1,0,0,	2,0,0,		1,1,0,		1,2,0},     //T
    			
    			{3,	2,0,0,		0,1,0,	1,1,0,	2,1,0,		2,2,0},
    			
    			{3,	1,0,0,		1,1,0,		0,2,0,	1,2,0,	2,2,0},
    			
    			{3,	0,0,0,		0,1,0,	1,1,0,	2,1,0,		0,2,0},
    			
    			
    			{3,	0,0,0,
    				0,0,1,		0,1,1,		0,2,1,
    				0,0,2},
    				
    				
    			{3,	0,0,0,		0,1,0,		0,2,0,
    							0,1,1,
    							0,1,2},
    							
    			{3,							0,2,0,
    				0,0,1,		0,1,1,		0,2,1,
    										0,2,2},
    										
    										
    			{3,				0,1,0,
    							0,1,1,
    				0,0,2,		0,1,2,		0,2,2},
    			
    			
    			{3,	0,0,0,	1,0,0,	2,0,0,
    						1,0,1,
    						1,0,2},
    						
    						
    			{3,					2,0,0,
    				0,0,1,	1,0,1,	2,0,1,
    								2,0,2},
    								
    								
    			{3,			1,0,0,
    						1,0,1,
    				0,0,2,	1,0,2,	2,0,2},
    				
    				
    			{3,	0,0,0,
    				0,0,1,	1,0,1,	2,0,1,
    				0,0,2}	
    			
    	
    	};

        public static void main(String[] args) {
                Bruteforce test = new Bruteforce();
                
                
                /*if(test.doesBoxFit(10, test.nextFreeCoord())){
                test.placeBox(10, test.nextFreeCoord());
                }
                */
                test.returnPercentFilled(test.container);
                test.printContainer();
                

        }

        // constructor
        public Bruteforce() {

                // set up stuff and call the backtracking

                
                myFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        		myFrame.setBounds(100, 100, 700, 500);
        		myFrame.setVisible(true);
        		myFrame.add(new Frame());
        		//backtracking(nextFreeCoord());
        		backtrackingPento(nextFreeCoord());
        }

        // public methods
        public int[][][] returnSolution() {
                return container;
        }

        private void backtracking(int[] coord) {
                OuterLoop: for (int boxNumber = 1; boxNumber <= boxes.length; boxNumber++) {
                        if (doesBoxFit(boxNumber, coord)) {
                                placeBox(boxNumber, coord);
                                myFrame.repaint();
                                //printContainer();

                                if (nextFreeCoord() == null) {
                                        // optimal solution has been found, yay!
                                        System.out.println("Container completely filled!");
                                        break OuterLoop;
                                        
                                } else {
                                        backtracking(nextFreeCoord());
                                }

                                removeBox(boxNumber, coord);
                        }

                }

        }
        
        
        private void backtrackingPento(int[] coord) {
            OuterLoop: for (int boxNumber = 1; boxNumber < pentos.length; boxNumber++) {
                    if (doesPentoFit(boxNumber, coord)) {
                            placePento(boxNumber, coord);
                            myFrame.repaint();
                            //printContainer();

                            if (nextFreeCoord() == null) {
                                    // optimal solution has been found, yay!
                                    System.out.println("Container completely filled!");
                                    break OuterLoop;
                                    
                            } else {
                                    backtracking(nextFreeCoord());
                            }

                            removePento(boxNumber, coord);
                    }

            }

    }

        private void removeBox(int boxNumber, int[] Coord) {
                for (int x = 0; x < boxes[(boxNumber - 1)][1]; x++) {
                        for (int y = 0; y < boxes[(boxNumber - 1)][2]; y++) {
                                for (int z = 0; z < boxes[(boxNumber - 1)][3]; z++) {
                                        /*
                                        System.out.println("Max X: " + boxes[(boxNumber - 1)][1]);
                                        System.out.println("Max Y: " + boxes[(boxNumber - 1)][2]);
                                        System.out.println("Max Z: " + boxes[(boxNumber - 1)][3]);

                                        System.out.println("X: " + x);
                                        System.out.println("Y: " + y);
                                        System.out.println("Z: " + z);
                                        */
                                        container[x+Coord[0]][y+Coord[1]][z+Coord[2]] = 0;
                                }
                        }
                }

        }
        
        
        public void removePento (int x, int[]coordinates){
        	int[][] input=pentos;
        	int[][][] cargo=container;
    		for (int a=1; (input[x].length)>a; a=a+3){
    		cargo[input[x][a]+coordinates[0]][input[x][a+2]+coordinates[2]][input[x][a+1]+coordinates[1]]=0;
    		}
    		
    	}
        
        
        

        private int[] nextFreeCoord() {

                for (int x = 0; x < container.length; x++) {
                        for (int y = 0; y < container[0].length; y++) {
                                for (int z = 0; z < container[0][0].length; z++) {
                                        if (container[x][y][z] == 0) {
                                                int[] freeCoord = { x, y, z };
                                                return freeCoord;
                                        }
                                }
                        }
                }

                return null;
        }
        
        

        private void placeBox(int boxNumber, int[] Coord) {

                for (int x = 0; x < boxes[(boxNumber - 1)][1]; x++) {
                        for (int y = 0; y < boxes[(boxNumber - 1)][2]; y++) {
                                for (int z = 0; z < boxes[(boxNumber - 1)][3]; z++) {
                                        
                                        container[x+Coord[0]][y+Coord[1]][z+Coord[2]] = boxNumber;
                                }
                        }
                }
                
                myTimer=new Timer(delay, new ActionListener(){

					
					public void actionPerformed(ActionEvent arg0) {
						myTimer.stop();
						
					}});
                myTimer.setInitialDelay(delay);
                myTimer.start();
                while(myTimer.isRunning()){
                	
                }
               
                
        }
        
        public void placePento (int x, int[]coordinates){
        	int[][] input=pentos;
        	int[][][] cargo=container;
    		for (int a=1; (input[x].length)>a; a=a+3){
    		cargo[input[x][a]+coordinates[0]][input[x][a+2]+coordinates[2]][input[x][a+1]+coordinates[1]]=input[x][0];
    		}
    		myTimer=new Timer(delay, new ActionListener(){

				
				public void actionPerformed(ActionEvent arg0) {
					myTimer.stop();
					
				}});
            myTimer.setInitialDelay(delay);
            myTimer.start();
            while(myTimer.isRunning()){
            	
            }
    	}

        private boolean doesBoxFit(int boxNumber, int[] Coord) {

                boolean allEmpty = true;

                OuterLoop: while (allEmpty) {

                        for (int x = 0; x < boxes[(boxNumber - 1)][1]; x++) {
                                for (int y = 0; y < boxes[(boxNumber - 1)][2]; y++) {
                                        for (int z = 0; z < boxes[(boxNumber - 1)][3]; z++) {

                                                try {
                                                        if (container[x+Coord[0]][y+Coord[1]][z+Coord[2]] != 0) {
                                                                System.out.println("Not all cells are empty");
                                                                allEmpty = false;
                                                                myFrame.repaint();
                                                                break OuterLoop;
                                                        }
                                                } catch (ArrayIndexOutOfBoundsException e) {
                                                        System.out.println("The pent overlapped the board");
                                                        allEmpty = false;
                                                        break OuterLoop;
                                                }

                                        }
                                }
                        }
                        
                        break OuterLoop;

                }
                return allEmpty;

        }
        
        
        private boolean doesPentoFit(int boxNumber, int[] Coord) {
        	
        	for (int a=1; (pentos[boxNumber].length)>a; a=a+3){



        		try {
        			if (container[pentos[boxNumber][a]+Coord[0]][pentos[boxNumber][a+2]+Coord[2]][pentos[boxNumber][a+1]+Coord[1]]==0){
        			}
        		}
        		
        		catch (ArrayIndexOutOfBoundsException e) {
        			return false;
        		}
        		
        	}
        	return true;
             		
             		
             		/*
             		
             		if(pentos[boxNumber][a]+Coord[0]>=0 && pentos[boxNumber][a+2]+Coord[2]>=0 && pentos[boxNumber][a+1]+Coord[1]>=0 &&     pentos[boxNumber][a]+Coord[0]<container.length && pentos[boxNumber][a+2]+Coord[2]<container[0][0].length && pentos[boxNumber][a+1]+Coord[1]<container[0].length &&        container[pentos[boxNumber][a]+Coord[0]][pentos[boxNumber][a+2]+Coord[2]][pentos[boxNumber][a+1]+Coord[1]]==0){
             			
             		}
             		else{
             			return false;
             		}
             	}
     			return true;
             */
    }

        // temp methods

        public double returnPercentFilled(int[][][] container) {

                int totalVolume = (container.length * container[0].length * container[0][0].length);
                int unitsFilled = 0;

                for (int x = 0; x < container.length; x++) {
                        for (int y = 0; y < container[0].length; y++) {
                                for (int z = 0; z < container[0][0].length; z++) {
                                        if (container[x][y][z] != 0) {
                                                unitsFilled++;
                                        }
                                }
                        }
                }
                System.out.println("Volume: " + totalVolume);
                System.out.println("Units filled " + unitsFilled);
                System.out.println("Percentage filled: " + (((double) unitsFilled) / totalVolume) + "%");
                return ((double) unitsFilled) / totalVolume;
        }

        public void printContainer() {
                for (int x = 0; x < container.length; x++) {
                        System.out.println("X=" + x);

                        for (int y = 0; y < container[0].length; y++) {
                                System.out.println(Arrays.toString(container[x][y]));
                        }
                }

        }
        
        
        class Frame extends JPanel{
    		
    		JPanel myPanel=new JPanel();

    		public Frame(){
    			
    		}

    		public void paint(Graphics g)
    		{
    			super.paint(g);
    			Graphics2D g2 = (Graphics2D)g;
    			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    			for (int a=0; a<container.length; a++){

    				for(int b=0; b<container[0].length; b++){

    					for(int c=0; c<container[0][0].length; c++){

    						int s=10;
    						if(container[a][b][c]==0){
    							g2.setColor(Color.GRAY);
    						//	g2.drawRect(c*s+b*(container[0][0].length+1)*s, a*s, s, s);
    						//	g2.fill3DRect(c*s+b*(container[0][0].length+1)*s, a*s, s, s, true);
    							g2.fill3DRect(a*s, c*s+b*(container[0][0].length+1)*s, s, s, true);
    						}
    						else{
    							g2.setColor(Color.RED);
    							//	g2.drawRect(c*s+b*(container[0][0].length+1)*s, a*s, s, s);
    							//	g2.fill3DRect(c*s+b*(container[0][0].length+1)*s, a*s, s, s, true);
    								g2.fill3DRect(a*s, c*s+b*(container[0][0].length+1)*s, s, s, true);
    							
    						}
    					}
    				}

    			}
    		}
    	}

}
